﻿@using Seal.Model;
@{
    ReportTask task = Model;

    task.TemplateDescription = "Build a list of object and loop for each object either sequentially or in parallel (using multiple threads).";

    //Parameters for this task
    task.Parameters.Add(new Parameter() { Name = "folder", Value = "", DisplayName = "1.List of string: Folder path", Description = "The input folder to build the list (of string)." + ReportTask.TranslatedParameterDescriptionFull, Enums = new string[] { @"%SEALREPOSITORY%/Reports", @"%SEALREPOSITORY%/Databases", ReportTask.ParentExecResultKeyword, ReportTask.ExecInputKeyword }, UseOnlyEnumValues = false });
    task.Parameters.Add(new Parameter() { Name = "filter", Value = "*.*", DisplayName = "1.List of string: File filter", Description = "The file filter to build the list.", Enums = new string[] { @"*.*", @"*.xlsx", @"*.csv", @"*.txt" }, UseOnlyEnumValues = false });
    task.Parameters.Add(new Parameter() { Name = "sql", Value = "", DisplayName = "2.List of DataRow: Select SQL", Description = "The SQL SELECT Statement to build the list (of DataRow)." + ReportTask.TranslatedParameterDescription });
    task.Parameters.Add(new Parameter() { Name = "excel_path", Value = "", DisplayName = "3.List of DataRow: Excel file Path", Description = "The Excel file path (*.xlsx) to build the list (of DataRow) from a sheet." + ReportTask.TranslatedParameterDescription, Enums = new string[] { @"%SEALREPOSITORY%/Databases/databank.worldbank.org_health_population.xlsx", ReportTask.ParentExecResultKeyword, ReportTask.ExecInputKeyword }, UseOnlyEnumValues = false });
    task.Parameters.Add(new Parameter() { Name = "excel_tab", Value = "", DisplayName = "3.List of DataRow: Excel tab name", Description = "The Tab name of the Excel Sheet used to load the table. If empty, the first tab is used." + ReportTask.TranslatedParameterDescription });
    task.Parameters.Add(new Parameter() { Name = "input", Value = "", DisplayName = "4.List of  object", Description = "Use an input from another task.", Enums = new string[] { "NONE|", "PARENTEXECRESULT|Use Parent Exec Result", "EXECINPUT|Use Exec Input" }, UseOnlyEnumValues = true });
    task.Parameters.Add(new Parameter() { Name = "thread", NumericValue = 1, DisplayName = "Number of threads", Description = "Number of threads used to execute child tasks. A value of 0 means a number of threads equals to the list count." });

    task.Script = @"@using System.IO
@using System.Threading
@{
    ReportTask task = Model;
    Report report = task.Report;
    var helper = new TaskHelper(task);
    
    var items = new List<object>();
    var folder = task.GetValueTranslated(""folder"");
    var sql = task.GetValueTranslated(""sql"");
    var thread = task.GetNumericValue(""thread"");
    var excel = task.GetValueTranslated(""excel_path"");
    
    //Folder input
    if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder)) {
        foreach (var file in Directory.GetFiles(folder, task.GetValue(""filter"")).Where(i => !Path.GetFileName(i).StartsWith(""~"")).OrderBy(i => i)) {
            items.Add(file);
        }
    }
    //SQL input
    else if (!string.IsNullOrEmpty(sql)) {
        var dataTable = helper.LoadDataTable(sql);
        foreach(var row in dataTable.Rows) {
            items.Add(row);
        }
    }    
    //Excel input
    else if (!string.IsNullOrEmpty(excel) && File.Exists(excel)) {
        var dataTable = DataTableLoader.FromExcel(excel, task.GetValueTranslated(""excel_tab""));
        foreach(var row in dataTable.Rows) {
            items.Add(row);
        }
    }
    //OR 
    //   fill the items collection with any relevant object

    if (thread == 0) {
        thread = items.Count;
    }
    
    task.LogMessage($""Processing {items.Count} item(s) using {thread} thread(s)"");
    var tasks = new List<Task>();
    for (int i=1; i<=thread && !report.Cancel && items.Count>0;i++) {
        tasks.Add(Task.Run(() => AsyncExec(items)));
        Thread.Sleep(100); 
    }
    
    while (!report.Cancel) {
        Thread.Sleep(100);
        if (!tasks.Exists(i => !i.IsCompleted)) {
            break;
        }    
    }    
}

@functions {
    async Task AsyncExec(List<object> items) {
    	ReportTask task = Model;
        Report report = task.Report;
        try {
            task.LogMessage($""Starting Thread"");
            
            while (true) {
                object item;
                lock (task) {
                    item = items.FirstOrDefault();
                    if (item != null) {
                        items.Remove(item);
                        task.LogMessage($""---------------------------------------------- {items.Count} Items left."");
                    }
                }
                if (report.Cancel || item == null) break;

                //Execute children
                foreach (var child in task.Tasks.Where(i=> i.Enabled).OrderBy(i => i.SortOrder))
                {                
                    if (report.Cancel) break;
                    child.InitParameters();
                    ReportTask newTask = (ReportTask) Helper.Clone(child);
                    newTask.Report = report;
                    newTask.InitReferences();

                    task.LogMessage($""Processing task {newTask.Name} for item {item.ToString()}"");
                    newTask.ExecInput = item;
                    newTask.Execute();
                }            
            }                
        }
        catch (Exception ex) {
            task.HandleException(ex);
        }
        finally {
            task.LogMessage($""Ending Thread"");
        }
    }
}
";

    task.BodyScript = ReportTask.NoChildrenBodyScriptTemplate;
}
